#include "warray/warray_hyper.h"
#include "test.h"

#include <iostream>

#include "custom_type.h"
#include "helper.h"

typedef boost::mpl::list< float,double,std::complex<float>,std::complex<double> > test_types;

BOOST_AUTO_TEST_CASE_TEMPLATE( array_sinh, T, test_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::sinh(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_sinh<T>())) );
	
	z = warp::sinh(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_sinh<T>())) );
	
	z = x.copy();
	warp::sinh(z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_sinh<T>())) );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( array_cosh, T, test_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::cosh(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_cosh<T>())) );
	
	z = warp::cosh(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_cosh<T>())) );
	
	z = x.copy();
	warp::cosh(z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_cosh<T>())) );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( array_tanh, T, test_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::tanh(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_tanh<T>())) );
	
	z = warp::tanh(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_tanh<T>())) );
	
	z = x.copy();
	warp::tanh(z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_tanh<T>())) );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( array_acosh, T, test_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	warp::cosh(x,x);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::acosh(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_acosh<T>())) );
	
	z = warp::acosh(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_acosh<T>())) );
	
	z = x.copy();
	warp::acosh(z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_acosh<T>())) );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( array_asinh, T, test_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	warp::sinh(x,x);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::asinh(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_asinh<T>())) );
	
	z = warp::asinh(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_asinh<T>())) );
	
	z = x.copy();
	warp::asinh(z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_asinh<T>())) );
}


BOOST_AUTO_TEST_CASE_TEMPLATE( array_atanh, T, test_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	warp::tanh(x,x);
	// For some reason it overflows with just one tanh, so we do it again
	// just to be on the safe side.
	warp::tanh(x,x);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::atanh(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_atanh<T>())) );
	
	z = warp::atanh(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_atanh<T>())) );
	
	z = x.copy();
	warp::atanh(z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_atanh<T>())) );
}
